#ifndef _CRT_ALLOC_h
#define _CRT_ALLOC_h

#include <crt_core.hpp>

#ifdef __cplusplus
extern "C" {
#endif

typedef unsigned char mm_char;
typedef unsigned int mm_uint_t;
typedef int mm_int_t;
typedef void* mm_buf_tag_t;

#define mm_memzero(buf, n)     bzero(buf, n)
#define mm_memset(buf, c, n)   (void)s_memset(buf, c, n)
#define mm_memcpy(dst, src, n) (void)s_memcpy(dst, src, n)

#define mm_memalign(alignment, size) mm_alloc(size)

#define MM_MAX_ALLOC_FROM_POOL 4097

#define MM_DEFAULT_POOL_SIZE (16 * 1024)

#define MM_POOL_ALIGNMENT 16

#define mm_align(d, a)     (((d) + (a - 1)) & ~(a - 1))
#define mm_align_ptr(p, a) (mm_char*)(((uintptr_t)(p) + ((uintptr_t)a - 1)) & ~((uintptr_t)a - 1))

#define MM_MIN_POOL_SIZE mm_align((sizeof(mm_pool_t) + 2 * sizeof(mm_pool_large_t)), MM_POOL_ALIGNMENT)

#ifndef MM_ALIGNMENT
#define MM_ALIGNMENT sizeof(unsigned long) /* platform word */
#endif

typedef void (*mm_pool_cleanup_pt)(void* data);

typedef struct mm_pool_s mm_pool_t;
typedef struct mm_chain_s mm_chain_t;
typedef struct mm_pool_large_s mm_pool_large_t;
typedef struct mm_pool_cleanup_s mm_pool_cleanup_t;

#define NGX_OK       0
#define NGX_ERROR    -1
#define NGX_AGAIN    -2
#define NGX_BUSY     -3
#define NGX_DONE     -4
#define NGX_DECLINED -5
#define NGX_ABORT    -6

typedef struct mm_buf_s mm_buf_t;

#pragma pack(push, 4)

struct mm_buf_s {
    mm_char* pos;
    mm_char* last;
    off_t file_pos;
    off_t file_last;

    mm_char* start; /* start of buffer */
    mm_char* end;   /* end of buffer */
    mm_buf_tag_t tag;
    mm_buf_t* shadow;
    unsigned temporary : 1;
    unsigned memory : 1;
    unsigned mmap : 1;

    unsigned recycled : 1;
    unsigned in_file : 1;
    unsigned flush : 1;
    unsigned sync : 1;
    unsigned last_buf : 1;
    unsigned last_in_chain : 1;

    unsigned last_shadow : 1;
    unsigned temp_file : 1;

    int num;
};

struct mm_chain_s {
    mm_buf_t* buf;
    mm_chain_t* next;
};

struct mm_pool_cleanup_s {
    mm_pool_cleanup_pt handler;
    void* data;
    mm_pool_cleanup_t* next;
};

struct mm_pool_large_s {
    mm_pool_large_t* next;
    void* alloc;
};

typedef struct {
    mm_char* last;
    mm_char* end;
    mm_pool_t* next;
    mm_uint_t failed;
} mm_pool_data_t;

struct mm_pool_s {
    mm_pool_data_t d;
    size_t max;
    mm_pool_t* current;
    mm_chain_t* chain;
    mm_pool_large_t* large;
    mm_pool_cleanup_t* cleanup;
};

#pragma pack(pop)

void* mm_alloc(size_t size);
void* mm_calloc(size_t size);
void mm_free(void* p);

mm_pool_t* mm_create_pool(size_t size);
void mm_destroy_pool(mm_pool_t* pool);
void mm_reset_pool(mm_pool_t* pool);

void* mm_palloc(mm_pool_t* pool, size_t size);
void* mm_pnalloc(mm_pool_t* pool, size_t size);
void* mm_pcalloc(mm_pool_t* pool, size_t size);
void* mm_pmemalign(mm_pool_t* pool, size_t size, size_t alignment);
mm_int_t mm_pfree(mm_pool_t* pool, void* p);

#ifdef __cplusplus
}
#endif

#endif
